/*
Spotter Exercise Manager
Copyright 2011 Evan Nelson.

This file is part of Spotter Exercise Manager.

Spotter Exercise Manager is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Spotter Exercise Manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Spotter Exercise Manager.  If not, see <http://www.gnu.org/licenses/>.

The author can be contacted by emailing ean5533@gmail.com
*/

#include "sectionweightlifting.h"
#include "ui_sectionweightlifting.h"

#include <QMessageBox>
#include <QRect>
#include <QSqlQuery>
#include <QKeyEvent>
#include <qwt_legend.h>

#include "src/database.h"
#include "src/settings.h"
#include "src/plotter.h"

#include "src/plot.h"
#include "src/weightlog.h"
#include "src/editexercises.h"

SectionWeightlifting::SectionWeightlifting(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SectionWeightlifting)
{
    ui->setupUi(this);

    tabsMain = ui->tabWeightlifting;
    ui->tabWeightlifting->setCurrentIndex(0);

    prepareLogs();
    prepareTemplates();
    prepareGraphs();

    refreshLogs();
    refreshTemplates();

    ui->tableLog->installEventFilter(this);
}

bool SectionWeightlifting::eventFilter(QObject *obj, QEvent *event) {
    //only specially handle keypress events, and specifically only on tableLog
    if((obj != ui->tableLog && obj != ui->tableTemplate) || event->type() != QEvent::KeyPress) {
        return QObject::eventFilter(obj, event);
    }

    //only specially handle keypress event if key was Enter or Return
    QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
    if(keyEvent->key() != Qt::Key_Enter && keyEvent->key() != Qt::Key_Return) {
        return QObject::eventFilter(obj, event);
    }

    viewOrEditCurrentLog();
    return true;
}

SectionWeightlifting::~SectionWeightlifting()
{
    delete ui;
}

void SectionWeightlifting::prepareLogs() {
    //set up tableLog context menu
    ui->tableLog->addAction(ui->actionDeleteLog);
    ui->tableLog->addAction(ui->actionEditLog);
    ui->tableLog->addAction(ui->actionViewLog);
    ui->tableLog->setContextMenuPolicy(Qt::ActionsContextMenu);

    //set up column header resizing (can't be done in designer version 2.1)
    ui->tableLog->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    ui->tableLog->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
    ui->tableLog->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);

    ui->tableLog->setColumnHidden(0, true);
}

void SectionWeightlifting::prepareTemplates() {
    //set up tableTemplate context menu
    ui->tableTemplate->addAction(ui->actionDeleteTemplate);
    ui->tableTemplate->addAction(ui->actionEditTemplate);
    ui->tableTemplate->setContextMenuPolicy(Qt::ActionsContextMenu);

    //set up column header resizing (can't be done in designer version 2.1)
    ui->tableTemplate->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    ui->tableTemplate->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);

    ui->tableTemplate->setColumnHidden(0, true);
}

void SectionWeightlifting::prepareGraphs() {
    ui->stackedWidgetGraphs->setCurrentIndex(0);

    //initialize preview to empty graph
    Plotter::buildEmptyPlot(ui->plotWtOverTime);
    ui->plotWtOverTime->hide();

    //prepare date boxes for WtOverTime
    ui->dateWtOverTime_From->setDate(QDate::currentDate().addYears(-2));
    ui->dateWtOverTime_To->setDate(QDate::currentDate());

    //prepare weight types combobox for WtOverTime
    ui->cmbWtOverTime_WtType->clear();
    QSqlQuery *query = Database::prepareQuery("SELECT weightType FROM weightType");
    query->exec();
    while(query->next()) {
        ui->cmbWtOverTime_WtType->addItem(query->value(0).toString());
    }
    delete query;
}

void SectionWeightlifting::on_tableLog_doubleClicked() {
    viewOrEditCurrentLog();
}

void SectionWeightlifting::viewOrEditCurrentLog() {
    if(ui->tableLog->currentRow() < 0) return;

    int curRow = ui->tableLog->currentRow();

    QTableWidgetItem *curLog = ui->tableLog->item(curRow, 0);
    int curLogInt = curLog->text().toInt();

    QTableWidgetItem *logStatus = ui->tableLog->item(curRow, 2);
    QString sStatus = logStatus->text();

    if(sStatus == "Completed") {
        viewLog(curLogInt);
    } else {
        editLog(curLogInt);
    }
}

void SectionWeightlifting::on_btnViewLog_clicked() {
    on_actionViewLog_triggered();
}

void SectionWeightlifting::on_btnEditLog_clicked() {
    on_actionEditLog_triggered();
}

void SectionWeightlifting::on_btnDeleteLog_clicked()
{
    on_actionDeleteLog_triggered();
}

void SectionWeightlifting::on_btnNewLog_clicked()
{
    newLog();
}

void SectionWeightlifting::refreshLogs() {
    ui->tableLog->clearContents();
    ui->tableLog->setRowCount(0);
    ui->tableLog->setSortingEnabled(false);

    QSqlQuery *query = Database::prepareQuery("SELECT LID, dateRecorded, status FROM WeightLog WHERE templateName IS NULL");
    query->exec();

    int row = 0;
    while(query->next()) {
        ui->tableLog->setRowCount(row+1);

        //left pad LogID with 0's
        QString sPaddedLID = QString("%1").arg(query->value(0).toString(), 5, '0');

        ui->tableLog->setItem(row, 0, new QTableWidgetItem(sPaddedLID));
        ui->tableLog->setItem(row, 1, new QTableWidgetItem(query->value(1).toString()));
        ui->tableLog->setItem(row, 2, new QTableWidgetItem(query->value(2).toString()));
        row++;
    }

    ui->tableLog->setSortingEnabled(true);
    ui->tableLog->sortByColumn(1, Qt::DescendingOrder);

    delete query;
}

void SectionWeightlifting::refreshTemplates() {
    ui->tableTemplate->clearContents();
    ui->tableTemplate->setRowCount(0);
    ui->tableTemplate->setSortingEnabled(false);

    QSqlQuery *query = Database::prepareQuery("SELECT LID, templateName FROM WeightLog WHERE templateName IS NOT NULL");
    query->exec();

    int row = 0;
    while(query->next()) {
        ui->tableTemplate->setRowCount(row+1);

        //left pad LogID with 0's
        QString sPaddedLID = QString("%1").arg(query->value(0).toString(), 5, '0');

        ui->tableTemplate->setItem(row, 0, new QTableWidgetItem(sPaddedLID));
        ui->tableTemplate->setItem(row, 1, new QTableWidgetItem(query->value(1).toString()));
        row++;
    }

    ui->tableTemplate->setSortingEnabled(true);
    ui->tableTemplate->sortByColumn(1, Qt::DescendingOrder);

    delete query;
}

void SectionWeightlifting::viewLog(int curLog) {
    WeightLog *frmWeightLog = new WeightLog(curLog, WeightLog::MODE_VIEW, this);
    frmWeightLog->show();
}

void SectionWeightlifting::editLog(int curLog) {
    WeightLog *frmWeightLog = new WeightLog(curLog, WeightLog::MODE_EDIT, this);
    frmWeightLog->exec();

    refreshLogs();
    prepareGraphs();
}

void SectionWeightlifting::newLog() {
    WeightLog *frmWeightLog = new WeightLog(-1, WeightLog::MODE_ADD, this);
    frmWeightLog->exec();

    refreshLogs();
    prepareGraphs();
}

void SectionWeightlifting::deleteLog(int curLog) {
    QSqlQuery *query = Database::prepareQuery("DELETE FROM Weightlifting WHERE logID = " + QString::number(curLog));
    query->exec();
    delete query;

    query = Database::prepareQuery("DELETE FROM WeightLog WHERE LID = " + QString::number(curLog));
    query->exec();
    delete query;

    refreshLogs();
}

void SectionWeightlifting::on_chkWtOverTime_From_stateChanged(int state)
{
    ui->dateWtOverTime_From->setEnabled((bool)state);
}

void SectionWeightlifting::on_chkWtOverTime_To_stateChanged(int state)
{
    ui->dateWtOverTime_To->setEnabled((bool)state);
}

void SectionWeightlifting::on_btnWtOverTime_AddEx_clicked()
{
    QString ex = ui->cmbWtOverTime_Ex->currentText();
    QString exWtType = ui->cmbWtOverTime_WtType->currentText();
    QString newItem = ex + " (" + exWtType + ")";

    //don't add an item multiple times
    if(ui->listWtOverTime->findItems(newItem, Qt::MatchExactly).size() > 0) {
        return;
    }

    ui->listWtOverTime->addItem(newItem);

    updateGraphPreview_WtOverTime();
}

void SectionWeightlifting::updateGraphPreview_WtOverTime() {
    QStringList exercises;
    for(int i = 0; i < ui->listWtOverTime->count(); i++) {
        exercises.append(ui->listWtOverTime->item(i)->text());
    }

    if(exercises.size() > 0) {
        updateGraphPreview_WtOverTime(exercises);
        ui->btnOpenWtOverTime->setEnabled(true);
    } else {
        ui->plotWtOverTime->hide();
        ui->btnOpenWtOverTime->setEnabled(false);
    }
}

void SectionWeightlifting::updateGraphPreview_WtOverTime(QStringList exercises) {
    Plotter::buildWtOverTimePlot(ui->plotWtOverTime, false, exercises);

    //no need for a title in the preview, just clutters things
    ui->plotWtOverTime->setTitle("");
    ui->plotWtOverTime->show();
}

void SectionWeightlifting::on_listWtOverTime_itemDoubleClicked(QListWidgetItem* item)
{
    item = item; //put here to nullify a warning
    ui->listWtOverTime->takeItem(ui->listWtOverTime->currentRow());

    updateGraphPreview_WtOverTime();
}

void SectionWeightlifting::on_btnOpenWtOverTime_clicked()
{
    if(ui->listWtOverTime->count() < 1) {
        QMessageBox("Select an exercise", "Please select at least one execise to plot",
                               QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec();
        return;
    }

    QStringList exercises;
    for(int i = 0; i < ui->listWtOverTime->count(); i++) {
        exercises.append(ui->listWtOverTime->item(i)->text());
    }

    QDate *minDate = 0;
    if(ui->chkWtOverTime_From->isChecked()) {
        minDate = new QDate(ui->dateWtOverTime_From->date());
    }

    QDate *maxDate = 0;
    if(ui->chkWtOverTime_To->isChecked()) {
        maxDate = new QDate(ui->dateWtOverTime_To->date());
    }

    Plot *plot = new Plot();
    plot->showWtOverTimePlot(exercises, minDate, maxDate);
    plot->show();
}

void SectionWeightlifting::on_actionDeleteLog_triggered()
{
    int curRow = ui->tableLog->currentRow();

    QTableWidgetItem *curLog = ui->tableLog->item(curRow, 0);
    if(curLog == 0) return;
    int curLogInt = curLog->text().toInt();

    int response = QMessageBox("Delete log #" + QString::number(curLogInt) + "?", "Are you sure you want to delete log #" + QString::number(curLogInt) + "? This action CANNOT be undone!",
                               QMessageBox::Question, QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton, this).exec();

    if(response == QMessageBox::Yes) {
        deleteLog(curLogInt);
    } else {
        return;
    }
}

void SectionWeightlifting::on_actionEditLog_triggered()
{
    int curRow = ui->tableLog->currentRow();

    QTableWidgetItem *curLog = ui->tableLog->item(curRow, 0);
    if(curLog == 0) return;
    int curLogInt = curLog->text().toInt();

    editLog(curLogInt);
}

void SectionWeightlifting::on_actionViewLog_triggered()
{
    int curRow = ui->tableLog->currentRow();

    QTableWidgetItem *curLog = ui->tableLog->item(curRow, 0);
    if(curLog == 0) return;
    int curLogInt = curLog->text().toInt();

    viewLog(curLogInt);
}

void SectionWeightlifting::on_btnEditExercises_clicked()
{
    loadEditExWindow();
}

void SectionWeightlifting::loadEditExWindow() {
    EditExercises *frmEditExercises = new EditExercises(EditExercises::MODE_WT, this);
    frmEditExercises->exec();

    //need to refesh areas of the program that use Exercise lists
    prepareGraphs();
}

void SectionWeightlifting::on_cmbWtOverTime_WtType_currentIndexChanged(int index)
{
    ui->cmbWtOverTime_Ex->setEnabled(false);
    ui->btnWtOverTime_AddEx->setEnabled(false);

    //prepare exercise list for graph0
    QString weightType = ui->cmbWtOverTime_WtType->itemText(index);
    ui->cmbWtOverTime_Ex->clear();

    QString sQuery = "SELECT exercise, dateRecorded"
                    " FROM (SELECT exercise, dateRecorded"
                    "       FROM Weightlifting w"
                    "       JOIN WeightLog l ON w.LogID = l.LID"
                    "       WHERE weightType = '" + weightType + "'"
                    "       AND oneRepMax IS NOT NULL"
                    "       GROUP BY exercise, dateRecorded)"
                    " GROUP BY exercise"
                    " HAVING count(exercise) > 1"
                    " ORDER BY exercise";
    QSqlQuery *query = Database::prepareQuery(sQuery);
    query->exec();
    while(query->next()) {
        ui->cmbWtOverTime_Ex->addItem(query->value(0).toString());
        ui->cmbWtOverTime_Ex->setEnabled(true);
    }
    delete query;
}

void SectionWeightlifting::on_cmbWtOverTime_Ex_currentIndexChanged(int index)
{
    if(index > -1) ui->btnWtOverTime_AddEx->setEnabled(true);
}

void SectionWeightlifting::on_toolButton_clicked()
{
    QMessageBox("Graph type info", "This button will eventually bring up some kind of information about the selected graph type... but for now all it does is show this messagebox. Be patient!",
                           QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec();
}

void SectionWeightlifting::on_btnNewTemplate_clicked()
{
    newTemplate();
}

void SectionWeightlifting::on_btnEditTemplate_clicked()
{
    on_actionEditTemplate_triggered();
}

void SectionWeightlifting::on_btnDeleteTemplate_clicked()
{
    on_actionDeleteTemplate_triggered();
}

void SectionWeightlifting::on_actionEditTemplate_triggered()
{
    int curRow = ui->tableTemplate->currentRow();

    QTableWidgetItem *curTemplate = ui->tableTemplate->item(curRow, 0);
    if(curTemplate == 0) return;
    int curTemplateInt = curTemplate->text().toInt();

    editTemplate(curTemplateInt);
}

void SectionWeightlifting::on_actionDeleteTemplate_triggered()
{
    int curRow = ui->tableTemplate->currentRow();

    QTableWidgetItem *curTemplate = ui->tableTemplate->item(curRow, 0);
    if(curTemplate == 0) return;
    int curTemplateInt = curTemplate->text().toInt();
    QString curTemplateName = ui->tableTemplate->item(curRow, 1)->text();

    int response = QMessageBox("Delete template?", "Are you sure you want to delete the template  named '" + curTemplateName + "'? This action CANNOT be undone!",
                            QMessageBox::Question, QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton, this).exec();

    if(response == QMessageBox::Yes) {
        deleteTemplate(curTemplateInt);
    } else {
        return;
    }
}

void SectionWeightlifting::editTemplate(int curTemplate) {
    WeightLog *frmWeightLog = new WeightLog(curTemplate, WeightLog::MODE_EDIT_TEMPLATE, this);
    frmWeightLog->exec();

    refreshTemplates();
}

void SectionWeightlifting::newTemplate() {
    WeightLog *frmWeightLog = new WeightLog(-1, WeightLog::MODE_ADD_TEMPLATE, this);
    frmWeightLog->exec();

    refreshTemplates();
}

void SectionWeightlifting::deleteTemplate(int curTemplate) {
    QSqlQuery *query = Database::prepareQuery("DELETE FROM Weightlifting WHERE logID = " + QString::number(curTemplate));
    query->exec();
    delete query;

    query = Database::prepareQuery("DELETE FROM WeightLog WHERE LID = " + QString::number(curTemplate));
    query->exec();
    delete query;

    refreshTemplates();
}

void SectionWeightlifting::on_tableTemplate_doubleClicked() {
    editCurrentTemplate();
}

void SectionWeightlifting::editCurrentTemplate() {
    if(ui->tableTemplate->currentRow() < 0) return;

    int curRow = ui->tableTemplate->currentRow();

    QTableWidgetItem *curTemplate = ui->tableTemplate->item(curRow, 0);
    int curTemplateInt = curTemplate->text().toInt();

    editTemplate(curTemplateInt);
}
